Completed
Push — master ( 7bde6b...85b016 )
by Maxence
02:01
created

nav.failedToAjax   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 1
nc 1
nop 0
1
/*
2
 * FullTextSearch - Full text search framework for Nextcloud
3
 *
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later. See the COPYING file.
6
 *
7
 * @author Maxence Lange <[email protected]>
8
 * @copyright 2018
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
26
/** global: OCA */
27
/** global: api */
28
/** global: search */
29
/** global: result */
30
/** global: settings */
31
32
33
34
var curr = {
35
	providerResult: [],
36
	page: 1,
37
	lastRequest: '',
38
	lastRequestTimer: null,
39
	lastRequestTimerQueued: false,
40
	lastRequestTimerForcing: false,
41
42
	setProviderResult: function (id, value) {
43
		curr.providerResult[id] = value;
44
	},
45
46
	getProviderResult: function (id) {
47
		var current = curr.providerResult[id];
48
		if (!current) {
49
			current = [];
50
		}
51
52
		return current;
53
	}
54
55
};
56
57
58
var nav = {
59
60
		manageDivProviderNavigation: function (divProviderNavigation, request, meta) {
61
62
			var maxPage = Math.ceil(meta.total / request.size);
63
64
			divProviderNavigation.attr('data-time', meta.time);
65
			divProviderNavigation.attr('data-page', request.page);
66
			divProviderNavigation.attr('data-options', JSON.stringify(request.options));
67
			divProviderNavigation.attr('data-search', request.search);
68
			divProviderNavigation.attr('data-max-page', maxPage);
69
			divProviderNavigation.attr('data-size', request.size);
70
			divProviderNavigation.attr('data-total', meta.total);
71
72
			var providerTitle = divProviderNavigation.attr('data-provider-title');
73
			var left = "Search " + providerTitle + " for '" + request.search + "' returned " +
74
				meta.total + " results in " + meta.time + "ms";
75
			divProviderNavigation.find('.provider_navigation_left').text(left);
76
77
			divProviderNavigation.find('.provider_navigation_curr').text(request.page + ' / ' +
78
				maxPage);
79
80
			divProviderNavigation.find('.provider_navigation_prev').stop().fadeTo(200,
81
				(request.page > 1) ? 1 : 0);
82
			divProviderNavigation.find('.provider_navigation_next').stop().fadeTo(200,
83
				(request.page < maxPage) ? 1 : 0);
84
		},
85
86
87
		manageDivProviderResult: function (divProviderResult, newResult, oldResult) {
88
			//replaceWith();
89
			nav.divProviderResultAddItems(divProviderResult, newResult, oldResult);
90
			if (oldResult) {
91
				nav.divProviderResultRemoveItems(divProviderResult, newResult, oldResult);
92
				nav.divProviderResultMoveItems(divProviderResult, newResult, oldResult);
93
			}
94
		},
95
96
97
		divProviderResultAddItems: function (divProviderResult, newResult, oldResult) {
98
99
			var precItem = null;
100
			for (var i = 0; i < newResult.length; i++) {
101
				var entry = newResult[i];
102
				if (result.getResultIndex(entry.id, oldResult) > -1) {
103
					precItem = nav.getDivResult(entry.id, divProviderResult);
104
					continue;
105
				}
106
107
				var divResult = nav.generateDivResult(entry, nav.generateTemplateEntry(entry));
108
				if (precItem === null) {
109
					divProviderResult.prepend(divResult);
110
				} else {
111
					precItem.after(divResult);
112
				}
113
114
				divResult.slideDown(settings.delay_result, function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
115
					$(this).children('.result_template').fadeTo(settings.delay_result, 1);
116
				});
117
118
				precItem = divResult;
119
			}
120
121
		},
122
123
124
		divProviderResultRemoveItems: function (divProviderResult, newResult, oldResult) {
125
			for (var i = 0; i < oldResult.length; i++) {
126
				var entry = oldResult[i];
127
				if (result.getResultIndex(entry.id, newResult) === -1) {
128
					var divResult = nav.getDivResult(entry.id, divProviderResult);
129
					divResult.fadeTo(settings.delay_result, 0, function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
130
						$(this).slideUp(settings.delay_result, function () {
131
							$(this).remove();
132
						});
133
					});
134
				}
135
			}
136
		},
137
138
139
		divProviderResultMoveItems: function (divProviderResult, newResult, oldResult) {
140
141
			var precId = '';
142
143
			oldResult = result.recalibrateResult(oldResult, newResult);
144
			newResult = result.recalibrateResult(newResult, oldResult);
145
			for (var i = 0; i < newResult.length; i++) {
146
				var entry = newResult[i];
147
148
				var pos = result.getResultIndex(entry.id, oldResult);
149
				if (pos > -1 && pos !== i) {
150
					nav.animateMoveDivResult(entry.id, divProviderResult, precId);
151
				}
152
153
				precId = newResult[i].id;
154
			}
155
		},
156
157
158
		animateMoveDivResult: function (entryId, divProviderResult, precId) {
159
160
			var divResult = nav.getDivResult(entryId, divProviderResult);
161
162
			if (precId === '') {
163
				divResult.fadeTo(settings.delay_result, 0.35, function () {
164
					$(this).prependTo(divProviderResult).fadeTo(100, 1);
165
				});
166
			} else {
167
				var precItem = nav.getDivResult(precId, divProviderResult);
168
				divResult.fadeTo(settings.delay_result, 0.35, function () {
169
					$(this).insertAfter(precItem).fadeTo(100, 1);
170
				});
171
			}
172
173
		},
174
175
176
		getDivProvider: function (providerId, providerName) {
177
			var ret = null;
178
			settings.resultContainer.children('.provider_header').each(function () {
179
				if ($(this).attr('data-id') === providerId) {
180
					ret = $(this);
181
				}
182
			});
183
184
			if (ret === null) {
185
				ret = nav.generateDivProvider(providerId, providerName);
186
				settings.resultContainer.append(ret);
187
			}
188
189
			return ret;
190
		},
191
192
193
		getDivResult: function (resultId, divProviderResult) {
194
			var ret = null;
195
			divProviderResult.children('.result_entry').each(function () {
196
				if ($(this).attr('data-id') === resultId) {
197
					ret = $(this);
198
				}
199
			});
200
201
			return ret;
202
		},
203
204
205
		fillDivResult: function (divResult, entry) {
206
			divResult.find('#title').text(entry.title);
207
			divResult.find('#score').text(entry.score);
208
209
			nav.fillDivResultExcepts(divResult, entry);
210
211
			if (entry.link !== '') {
212
				divResult.on('click', function () {
213
					window.open(entry.link, '_self');
214
				});
215
				divResult.find('div').each(function () {
216
					$(this).css('cursor', 'pointer');
217
				});
218
			}
219
		},
220
221
222
		/**
223
		 * @namespace entry.excerpts
224
		 */
225
		fillDivResultExcepts: function (divResult, entry) {
226
			if (entry.excerpts === null) {
227
				return;
228
			}
229
230
			if (entry.excerpts.length > 0) {
231
				divResult.find('#line1').text(entry.excerpts[0]);
232
			}
233
234
			if (entry.excerpts.length > 1) {
235
				divResult.find('#line2').text(entry.excerpts[1]);
236
			}
237
238
		},
239
240
		onEntryGenerated: function (divResult) {
241
242
			nav.deleteEmptyDiv(divResult, '#line1');
243
			nav.deleteEmptyDiv(divResult, '#line2');
244
245
			if (settings.parentHasMethod('onEntryGenerated')) {
246
				settings.parent.onEntryGenerated(divResult);
247
			}
248
		},
249
250
		onSearchRequest: function (data) {
251
			if (settings.parentHasMethod('onSearchRequest')) {
252
				settings.parent.onSearchRequest(data);
253
			}
254
		},
255
256
		onSearchReset: function () {
257
			if (settings.parentHasMethod('onSearchReset')) {
258
				settings.parent.onSearchReset();
259
			}
260
		},
261
262
		onResultDisplayed: function (data) {
263
			if (settings.parentHasMethod('onResultDisplayed')) {
264
				settings.parent.onResultDisplayed(data);
265
			}
266
		},
267
268
		onResultClose: function () {
269
			if (settings.parentHasMethod('onResultClose')) {
270
				settings.parent.onResultClose();
271
			}
272
		},
273
274
		onError: function (data) {
275
			if (settings.parentHasMethod('onError')) {
276
				settings.parent.onError(data);
277
			}
278
		},
279
280
		deleteEmptyDiv: function (entry, divId) {
281
			var div = entry.find(divId);
282
			if (div.text() === '') {
283
				div.remove();
284
			}
285
		},
286
287
288
		generateTemplateEntry: function (document) {
289
			var divTemplate = settings.entryTemplate;
290
			if (divTemplate === null) {
291
				divTemplate = settings.generateDefaultTemplate();
292
			}
293
294
			if (!divTemplate.length) {
295
				console.log('FullTextSearch Error: template_entry is not defined');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
296
				return;
297
			}
298
299
			var tmpl = divTemplate.html();
300
			tmpl = tmpl.replace(/%%id%%/g, escapeHTML(document.id));
301
302
			var div = $('<div>', {class: 'result_template'});
303
			div.html(tmpl).fadeTo(0);
304
305
			return div;
306
		},
307
308
309
		generateDivResult: function (entry, divResultContent) {
310
			var divResult = $('<div>', {class: 'result_entry'});
311
			divResult.hide();
312
			divResult.attr('data-id', entry.id);
313
			divResult.attr('data-link', entry.link);
314
			divResult.attr('data-result', JSON.stringify(entry));
315
			divResult.append(divResultContent);
316
317
			nav.fillDivResult(divResult, entry);
318
			nav.onEntryGenerated(divResult);
319
320
			return divResult;
321
		},
322
323
324
		generateDivProvider: function (providerId, providerName) {
325
326
327
			var divProviderNavigation = $('<div>', {class: 'provider_navigation'});
328
			divProviderNavigation.attr('data-provider-id', providerId);
329
			divProviderNavigation.attr('data-provider-title', providerName);
330
			divProviderNavigation.append($('<div>', {class: 'provider_navigation_left'}));
331
332
			var divProviderPagination = $('<div>', {class: 'provider_navigation_right'});
333
			var divProviderPaginationPrev = $('<div>', {class: 'icon-page-prev provider_navigation_prev'});
334
			divProviderPaginationPrev.on('click', function () {
335
				fullTextSearch.search({
0 ignored issues
show
Bug introduced by
The variable fullTextSearch seems to be never declared. If this is a global, consider adding a /** global: fullTextSearch */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
336
					providers: providerId,
337
					options: JSON.parse(divProviderNavigation.attr('data-options')),
338
					search: divProviderNavigation.attr('data-search'),
339
					page: Number(divProviderNavigation.attr('data-page')) - 1,
340
					size: divProviderNavigation.attr('data-size')
341
				});
342
			});
343
			divProviderPagination.append(divProviderPaginationPrev);
344
345
			divProviderPagination.append($('<div>', {class: 'provider_navigation_curr'}));
346
347
			var divProviderPaginationNext = $('<div>', {class: 'icon-page-next provider_navigation_next'});
348
			divProviderPaginationNext.on('click', function () {
349
				fullTextSearch.search({
0 ignored issues
show
Bug introduced by
The variable fullTextSearch seems to be never declared. If this is a global, consider adding a /** global: fullTextSearch */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
350
					providers: providerId,
351
					options: JSON.parse(divProviderNavigation.attr('data-options')),
352
					search: divProviderNavigation.attr('data-search'),
353
					page: Number(divProviderNavigation.attr('data-page')) + 1,
354
					size: divProviderNavigation.attr('data-size')
355
				});
356
			});
357
			divProviderPagination.append(divProviderPaginationNext);
358
359
			if (settings.searchProviderId !== '') {
360
				var divProviderPaginationClose = $('<div>',
361
					{class: 'icon-close provider_navigation_close'});
362
				divProviderPaginationClose.on('click', function () {
363
					nav.onResultClose();
364
				});
365
				divProviderPagination.append(divProviderPaginationClose);
366
			}
367
368
369
			divProviderNavigation.append(divProviderPagination);
370
371
			var divProviderResult = $('<div>', {class: 'provider_result'});
372
373
			var divProvider = $('<div>', {class: 'provider_header'});
374
			divProvider.hide();
375
			divProvider.attr('data-id', providerId);
376
			divProvider.append(divProviderNavigation);
377
			divProvider.append(divProviderResult);
378
379
			return divProvider;
380
		}
381
382
	}
383
;
384